//
//  ViewController.m
//  ThreadTest
//
//  Created by wp w on 12-6-14.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "ViewController.h"
#import "SellTickets.h"
#import "SellTickets2.h"
#import "SellTickets3.h"
#import "SellTicketsOperation.h"
#import "PageLoadOperation.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    
    ticketsCondition = [[NSCondition alloc] init];
    queue = [[NSOperationQueue alloc]init];
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    
    [ticketsCondition release];
    ticketsCondition = nil;
    [queue release];
    queue = nil;
}

-(void)dealloc{
    [ticketsCondition release];
    [queue release];
    [super dealloc];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

#pragma mark - thread
- (IBAction)threadTest {
    //线程创建主要有3种方式：
    //1.- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
    //    这种方式是先得到线程对象，然后可以对线程对象做一些操作（比如设置线程名），然后start启动
    //    比较灵活
    //2.+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
    //  这种方式直接生成一个线程，比较简单
    //3.- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
    //  NSObject类的方法，其他和方法2基本一样
    
    //线程创建方式1
    SellTickets *st=[[SellTickets alloc] init]; 
    [st setDelegate:self];
    [st ticket];   
    [st release]; 
    
    //线程创建方式2
    SellTickets2 *st2=[[SellTickets2 alloc] init]; 
    [st2 ticket:self];   
    [st2 release]; 
    
    //线程创建方式3
    SellTickets3 *st3=[[SellTickets3 alloc] init]; 
    [st3 ticket:self];   
    [st3 release]; 
}

- (void)refreshThreadTitle:(NSNumber*)i
{
    UIButton *btn = (UIButton*)[self.view viewWithTag:100];
    btn.titleLabel.font = [UIFont systemFontOfSize:10];
    if([i intValue] == 0)
    {
        [btn setTitle:@"sell tickets" forState:UIControlStateNormal];
    }
    else 
    {
        [btn setTitle:@"sell out" forState:UIControlStateNormal];
    }
}

#pragma mark - NSOperationQueue

//这个是使用NSOperation模拟卖票程序（其中用到了锁），但是失败了！！
//是不是NSOperation，只是为了防止主线程堵塞？
- (IBAction)operationQueueTest {
    //对于iOS来说，建议在尽可能的情况下避免直接操作线程，使用比如NSOperationQueue这样的机制。
    //可以把NSOperationQueue看作一个线程池，可往线程池中添加操作（NSOperation）
    //NSOperation
    
    
    tickets = 10;
    
//    //NSOperationQueue，可以新建，也可以使用本地共享队列
//    [[MyAppDelegate sharedOperationQueue] addOperation:theOp];
//    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//    //控制线程池中的并发的线程数
//    [queue setMaxConcurrentOperationCount: 2];
    
    SellTicketsOperation *task = [[SellTicketsOperation alloc]init];
    task.name = @"task1";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    [queue addOperation:task];
    [task release];
    
    task = [[SellTicketsOperation alloc]init];
    task.name = @"task2";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    [queue addOperation:task];
    [task release];
    
    task = [[SellTicketsOperation alloc]init];
    task.name = @"task3";
    task.tickets = &tickets;
    task.ticketsCondition = ticketsCondition;
    task.controller = self;
    //处理操作之间的依赖关系
    if ([[queue operations] count]>0) { 
        SellTicketsOperation *theBeforeTask=[[queue operations] lastObject]; 
        [task addDependency:theBeforeTask]; 
    }
    [queue addOperation:task];
    [task release];
    
    //    [queue release];
}


//NSOperation
//封装一个操作，然后把该操作加入到操作队列
//目的，防止阻塞主线程
- (IBAction)OperationTest {
    NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
    [array addObject:@"http://www.google.com"];
    [array addObject:@"http://www.apple.com"];
    [array addObject:@"http://www.yahoo.com"];
    [array addObject:@"http://www.zarrastudios.com"];
    [array addObject:@"http://www.macosxhints.com"];

    [queue setMaxConcurrentOperationCount:2];
    for (NSString *urlString in array) {
        NSURL *url = [NSURL URLWithString:urlString];
        PageLoadOperation *plo = [[PageLoadOperation alloc] initWithURL:url];
        plo.controller = self;
        [queue addOperation:plo];
        [plo release];
    }
}

- (void)pageLoaded:(NSString *)document;
{
    NSLog(@"%s Do something with the NSString: %@", _cmd, document);
}


//NSInvocationOperation
//把一个函数变为多线程
//目的，防止阻塞主线程
- (IBAction)InvocationOperationTest {
    //创建一个NSInvocationOperation对象，并初始化到方法
    //在这里，selector参数后的值是你想在另外一个线程中运行的方法（函数，Method）
    //在这里，object后的值是想传递给前面方法的数据
    NSString* data = @"hello";
    NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTaskMethod:) object:data];
    [queue addOperation:theOp];
    [theOp release];
}


// 这个是真正运行在另外一个线程的“方法”
- (void)myTaskMethod:(id)data
{
    // Perform the task.
    NSLog(@"%@", data);
    
    NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithInt:103], @"tag", data, @"title", nil];
    NSLog(@"%@",dic);
    [self performSelectorOnMainThread:@selector(refresh:) withObject:dic waitUntilDone:YES];
    [dic release];
}

- (void)refresh:(NSDictionary*)dic
{
    NSNumber* tag = [dic objectForKey:@"tag"];
    NSString* title = [dic objectForKey:@"title"];
    UIButton *btn = (UIButton*)[self.view viewWithTag:[tag intValue]];
    btn.titleLabel.font = [UIFont systemFontOfSize:10];
    [btn setTitle:title forState:UIControlStateNormal];
}


#pragma mark - NSRunLoop
/*
 1.runloop != while or for语句 
 2.每个线程都有自己的NSRunLoop，他们是程序自己建立的 
 3.并不是所以线程都需要使用它的NSRunLoop. 如果线程的runloop没有自己的input source，它不会运行。 
 4.以下几个情况是需要用线程的runloop 
   Use ports or custom input sources to communicate with other threads. 
   Use timers on the thread. 
   Use any of the performSelector… methods in a Cocoa application. 
   Keep the thread around to perform periodic tasks. 
 5. - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait 这样的语句实际上就是在向Main Thread的runloop对象添加input source. 
 */
- (IBAction)RunLoopRunTest {
    NSLog(@"RunLoopRunTest");
    
    pageStillLoading = YES;
    
    //一种紧凑的方式
    //阻塞式执行一段耗时程序，但是又不能阻塞界面响应。执行完后，继续执行后续操作
    //一种应用方式：某个界面需要登陆后才能浏览，如果未登陆，弹出登陆界面，登陆后自动回到原来的界面
    //现象是：只有该btn是蓝色的（即点击状态），也就是说其他的控件都是可以响应的
    [NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil];
    
    //如果直接使用sleep，那么所有的控件都不会响应
    //[NSThread sleepForTimeInterval:10];
    
    //while+NSRunLoop相当于windows中的循环消息处理，即一个嵌套的消息循环
    //程序代码只有执行完while后，才会继续执行
    while (pageStillLoading) 
    {
        //它相当于windows中的消息响应
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
}

- (void)loadPageInBackground:(id)object{
    NSLog(@"loadPageInBackground");
    [NSThread sleepForTimeInterval:10];
    
    //在这虽然可以直接调用函数改变pageStillLoading状态
    //但是这是错误的，因为这是在子线程中改变的。主线程的消息监控函数如果没有响应的话，就不会继续往下执行
    //应该使用performSelectorOnMainThread函数通知主线程，此时主线程消息循环收到消息，循环处理，然后退出循环，继续执行
    //[self setLoadPageInBackground:[NSNumber numberWithBool:NO]];
    
    //只好使用performSelectorOnMainThread和主线程通讯，哪怕不更新ui
    [self performSelectorOnMainThread:@selector(setLoadPageInBackground:) withObject:[NSNumber numberWithBool:NO] waitUntilDone:NO];
}

- (void)setLoadPageInBackground:(NSNumber*)status{
    NSLog(@"setLoadPageInBackground");
    pageStillLoading = [status boolValue];
}



@end
